Imports Cfg = System.Configuration
Imports Gen = System.Collections.Generic
Imports Glo = System.Globalization
Imports Iou = System.IO
Imports Ref = System.Reflection
Imports Sys = System
Imports Tex = System.Text
Imports W3c = System.Xml

Namespace Enhancements.Core.Logging
    <DebuggerStepThrough()> _
    Friend NotInheritable Class ___ConfigurationFile

        Private Shared __XmlSchemaBytes() As System.Byte = CType(Sys.Array.CreateInstance(GetType(System.Byte), 0), Byte())

        Private Sub New()
        End Sub

        Private Shared __InitializeCalled As System.Boolean = False
        Friend Shared ReadOnly Property ___InitializeCalled() As System.Boolean
            Get
                Return __InitializeCalled
            End Get
        End Property
        Friend Shared Sub ___Initialize()
            ___Assert.___IsInitializedNot("___ConfigurationFile[type]", ___InitializeCalled, True)
            ___Assert.___IsDisposedNot("___ConfigurationFile[type]", ___DisposeCalled, True)
            __InitializeCalled = True

            Dim _stream As Iou.Stream = Ref.Assembly.GetExecutingAssembly().GetManifestResourceStream("___ConfigurationFile.xsd")
            Dim _xmlSchemaBytes(CType(_stream.Length, Sys.Int32) - 1) As System.Byte
            _stream.Read(_xmlSchemaBytes, 0, _xmlSchemaBytes.Length)
            _stream.Dispose()

            ___Assert.___IsXmlSchemaValid("_xmlSchemaBytes", _xmlSchemaBytes, True)
            __XmlSchemaBytes = _xmlSchemaBytes
        End Sub

        Private Shared __DisposeCalled As System.Boolean = False
        Friend Shared ReadOnly Property ___DisposeCalled() As System.Boolean
            Get
                Return __DisposeCalled
            End Get
        End Property
        Friend Shared Sub ___Dispose()
            ___Assert.___IsInitialized("___ConfigurationFile[type]", ___InitializeCalled, True)
            ___Assert.___IsDisposedNot("___ConfigurationFile[type]", ___DisposeCalled, True)
            __DisposeCalled = True
        End Sub

        Friend Shared Function ___LoadServerBuild() As Gen.List(Of Log)
            ___Assert.___IsInitialized("___ConfigurationFile[type]", ___InitializeCalled, True)
            ___Assert.___IsDisposedNot("___ConfigurationFile[type]", ___DisposeCalled, True)
            ___Assert.___IsArrayEmptyNot("__XmlSchemaBytes", __XmlSchemaBytes, True)

            Dim _stream As Iou.Stream = Ref.Assembly.GetExecutingAssembly().GetManifestResourceStream("___ConfigurationFileServerBuild.xml")
            Dim _xmlBytes(CType(_stream.Length, Sys.Int32) - 1) As System.Byte
            _stream.Read(_xmlBytes, 0, _xmlBytes.Length)
            _stream.Dispose()
            ___Assert.___IsXmlValid("_xmlBytes", _xmlBytes, __XmlSchemaBytes, True)

            Dim _xmlDocument As W3c.XmlDocument = New W3c.XmlDocument()
            _stream = New Iou.MemoryStream(_xmlBytes)
            _xmlDocument.Load(_stream)
            _stream.Dispose()

            Return __Interpret(_xmlDocument)
        End Function

        Friend Shared Function ___LoadClientLaunch() As Gen.List(Of Log)
            ___Assert.___IsInitialized("___ConfigurationFile[type]", ___InitializeCalled, True)
            ___Assert.___IsDisposedNot("___ConfigurationFile[type]", ___DisposeCalled, True)
            ___Assert.___IsArrayEmptyNot("__XmlSchemaBytes", __XmlSchemaBytes, True)

            Dim _returnValue As Gen.List(Of Log) = Nothing

            Dim _path As System.String = Cfg.ConfigurationManager.AppSettings("Enhancements.Core.Logging.___ConfigurationFile.Path")
            If ___Assert.___IsNullNot("_path", _path, False) Then
                ___Assert.___IsFileExistent("_path", _path, True)

                Dim _xmlDocument As W3c.XmlDocument = __Load(_path)
                _returnValue = __Interpret(_xmlDocument)
            End If

            Return _returnValue
        End Function

        Friend Shared Function ___LoadClientRun(ByVal _path As System.String) As Gen.List(Of Log)
            ___Assert.___IsInitialized("___ConfigurationFile[type]", ___InitializeCalled, True)
            ___Assert.___IsDisposedNot("___ConfigurationFile[type]", ___DisposeCalled, True)
            ___Assert.___IsArrayEmptyNot("__XmlSchemaBytes", __XmlSchemaBytes, True)
            ___Assert.___IsFileExistent("_path", _path, True)

            Dim _xmlDocument As W3c.XmlDocument = __Load(_path)
            Return __Interpret(_xmlDocument)
        End Function

        Private Shared Function __Load(ByVal _path As System.String) As W3c.XmlDocument
            Dim _xmlBytes() As System.Byte = Iou.File.ReadAllBytes(_path)
            ___Assert.___IsXmlValid("_xmlBytes", _xmlBytes, __XmlSchemaBytes, True)

            Dim _returnValue As W3c.XmlDocument = New W3c.XmlDocument()
            _returnValue.Load(_path)

            Return _returnValue
        End Function

        Private Shared Function __Interpret(ByVal _xmlDocument As W3c.XmlDocument) As Gen.List(Of Log)
            Dim _logsObject As Gen.List(Of Log) = New Gen.List(Of Log)
            For Each _logNode As W3c.XmlNode In _xmlDocument.SelectNodes("Enhancements.Core.Logging.___ConfigurationFile/Log")

                Dim _logObject As Log
                _logObject = New Log()

                For Each _levelMappingNode As W3c.XmlNode In _logNode.SelectSingleNode("LevelMappings").ChildNodes
                    Dim _level As Level = CType([Enum].Parse(GetType(Level), _levelMappingNode.SelectSingleNode("Level").FirstChild.Value), Level)
                    Dim _overridesDescendants As System.Boolean = Sys.Boolean.Parse(_levelMappingNode.SelectSingleNode("OverridesDescendants").FirstChild.Value)
                    Select Case _levelMappingNode.Name
                        Case "LevelMappingGlobal"
                            _logObject.LevelMappings.Global.Level = _level
                            _logObject.LevelMappings.Global.OverridesDescendants = _overridesDescendants
                        Case "LevelMappingAssembly"
                            Dim _assembly As Ref.Assembly = Ref.Assembly.ReflectionOnlyLoad(_levelMappingNode.SelectSingleNode("Assembly").FirstChild.Value)
                            _logObject.LevelMappings.Add(New LevelMappingAssembly(_assembly, _level, _overridesDescendants))
                        Case "LevelMappingType"
                            Dim _type As Sys.Type = Sys.Type.ReflectionOnlyGetType(_levelMappingNode.SelectSingleNode("Type").FirstChild.Value, False, True)
                            _logObject.LevelMappings.Add(New LevelMappingType(_type, _level, _overridesDescendants))
                    End Select
                Next _levelMappingNode

                For Each _writerNode As W3c.XmlNode In _logNode.SelectNodes("Writers/Writer")
                    Dim _use As System.Boolean = Sys.Boolean.Parse(_writerNode.SelectSingleNode("Use").FirstChild.Value)
                    Select Case _writerNode.FirstChild.Name
                        Case "FileSystemWriterSingleFile"
                            Dim _folder As System.String = _writerNode.FirstChild.SelectSingleNode("Folder").FirstChild.Value
                            Dim _deleteOnStartup As System.Boolean = Sys.Boolean.Parse(_writerNode.FirstChild.SelectSingleNode("DeleteOnStartup").FirstChild.Value)
                            Dim _file As System.String = _writerNode.FirstChild.SelectSingleNode("File").FirstChild.Value
                            Dim _writerConfigurationObject As FileSystemWriterConfigurationSingleFile
                            _writerConfigurationObject = New FileSystemWriterConfigurationSingleFile(_file, _folder, _deleteOnStartup)
                            _logObject.Writers.Add(New FileSystemWriter(_writerConfigurationObject, __InterpretFormatter(_writerNode), _use))
                        Case "FileSystemWriterMultipleFiles"
                            Dim _folder As System.String = _writerNode.FirstChild.SelectSingleNode("Folder").FirstChild.Value
                            Dim _deleteOnStartup As System.Boolean = Sys.Boolean.Parse(_writerNode.FirstChild.SelectSingleNode("DeleteOnStartup").FirstChild.Value)
                            Dim _filePattern As System.String = _writerNode.FirstChild.SelectSingleNode("FilePattern").FirstChild.Value
                            Dim _newFileCreationCriteriaBytesCount As Sys.Int32 = Sys.Int32.Parse(_writerNode.FirstChild.SelectSingleNode("NewFileCreationCriteriaBytesCount").FirstChild.Value, Glo.CultureInfo.InvariantCulture)
                            Dim _newFileCreationCriteriaWritesCount As Sys.Int32 = Sys.Int32.Parse(_writerNode.FirstChild.SelectSingleNode("NewFileCreationCriteriaWritesCount").FirstChild.Value, Glo.CultureInfo.InvariantCulture)
                            Dim _writerConfigurationObject As FileSystemWriterConfigurationMultipleFiles
                            _writerConfigurationObject = New FileSystemWriterConfigurationMultipleFiles(_filePattern, _newFileCreationCriteriaBytesCount, _newFileCreationCriteriaWritesCount, _folder, _deleteOnStartup)
                            _logObject.Writers.Add(New FileSystemWriter(_writerConfigurationObject, __InterpretFormatter(_writerNode), _use))
                        Case "ConsoleWriter"
                            Dim _encoding As Tex.Encoding = Nothing
                            Select Case _writerNode.FirstChild.SelectSingleNode("Encoding").FirstChild.Value
                                Case "Ascii"
                                    _encoding = Tex.ASCIIEncoding.ASCII
                                Case "Utf7"
                                    _encoding = Tex.ASCIIEncoding.UTF7
                                Case "Utf8"
                                    _encoding = Tex.ASCIIEncoding.UTF8
                                Case "Utf32"
                                    _encoding = Tex.ASCIIEncoding.UTF32
                            End Select
                            Dim _writerConfigurationObject As ConsoleWriterConfiguration
                            _writerConfigurationObject = New ConsoleWriterConfiguration(_encoding)
                            _logObject.Writers.Add(New ConsoleWriter(_writerConfigurationObject, __InterpretFormatter(_writerNode), _use))
                    End Select
                Next _writerNode

                _logObject.Use = Sys.Boolean.Parse(_logNode.SelectSingleNode("Use").FirstChild.Value)

                _logsObject.Add(_logObject)
            Next _logNode

            Return _logsObject
        End Function

        Private Shared Function __InterpretFormatter(ByVal _writerNode As W3c.XmlNode) As Formatter
            Dim _returnValue As Formatter = Nothing

            Select Case _writerNode.FirstChild.NextSibling.Name
                Case "XmlFormatter"
                    Dim _encoding As Tex.Encoding = Nothing
                    Select Case _writerNode.FirstChild.NextSibling.SelectSingleNode("Encoding").FirstChild.Value
                        Case "Ascii"
                            _encoding = Tex.ASCIIEncoding.ASCII
                        Case "Utf7"
                            _encoding = Tex.ASCIIEncoding.UTF7
                        Case "Utf8"
                            _encoding = Tex.ASCIIEncoding.UTF8
                        Case "Utf32"
                            _encoding = Tex.ASCIIEncoding.UTF32
                    End Select
                    Dim _indentationUse As System.Boolean = Sys.Boolean.Parse(_writerNode.FirstChild.NextSibling.SelectSingleNode("IndentationUse").FirstChild.Value)
                    Dim _indentationLength As System.Int32 = Sys.Int32.Parse(_writerNode.FirstChild.NextSibling.SelectSingleNode("IndentationLength").FirstChild.Value, Glo.CultureInfo.InvariantCulture)
                    Dim _indentationCharacter As System.Char = _writerNode.FirstChild.NextSibling.SelectSingleNode("IndentationCharacter").FirstChild.Value.Chars(0)
                    Dim _xmlFormatterObject As XmlFormatter = New XmlFormatter(New XmlFormatterConfiguration(_encoding, _indentationUse, _indentationLength, _indentationCharacter))

                    _returnValue = _xmlFormatterObject
                Case "SingleLineFormatter"
                    Dim _encoding As Tex.Encoding = Nothing
                    Select Case _writerNode.FirstChild.NextSibling.SelectSingleNode("Encoding").FirstChild.Value
                        Case "Ascii"
                            _encoding = Tex.ASCIIEncoding.ASCII
                        Case "Utf7"
                            _encoding = Tex.ASCIIEncoding.UTF7
                        Case "Utf8"
                            _encoding = Tex.ASCIIEncoding.UTF8
                        Case "Utf32"
                            _encoding = Tex.ASCIIEncoding.UTF32
                    End Select
                    Dim _separationCharacter As System.Char = _writerNode.FirstChild.NextSibling.SelectSingleNode("SeparationCharacter").FirstChild.Value.Chars(0)
                    Dim _singleLineFormatterObject As SingleLineFormatter = New SingleLineFormatter(New SingleLineFormatterConfiguration(_encoding, _separationCharacter))

                    _returnValue = _singleLineFormatterObject
            End Select

            Return _returnValue
        End Function

    End Class
End Namespace
